Skip to content

feat: Add execution statistics storage and dashboard graph#1896

Merged
vcastellm merged 6 commits intomainfrom
feature/execution-statistics
Jan 28, 2026
Merged

feat: Add execution statistics storage and dashboard graph#1896
vcastellm merged 6 commits intomainfrom
feature/execution-statistics

Conversation

@vcastellm
Copy link
Copy Markdown
Member

@vcastellm vcastellm commented Jan 25, 2026

  • Add ExecutionStat data structure for daily execution counts
  • Implement GetExecutionStats and IncrementExecutionStat in storage
  • Update SetExecutionDone to track statistics on execution completion
  • Add GET /v1/stats API endpoint with configurable days parameter
  • Create ExecutionStatsChart React component with stacked area chart
  • Integrate statistics graph into UI dashboard
  • Add comprehensive tests for execution statistics functionality
  • Fix pre-existing import path issue in grpc_test.go

Proposed changes

Describe the big picture of your changes here to communicate to the maintainers why we should accept this pull request.
If it fixes a bug or resolves a feature request, be sure to link to that issue.

Types of changes

What types of changes does your code introduce?
Put an x in the boxes that apply

  • Bugfix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Documentation Update (if none of the other choices apply)

Summary by CodeRabbit

  • New Features

    • Added an execution statistics API endpoint to retrieve daily stats with a configurable lookback (defaults to 30 days).
    • Added a dashboard chart showing 30-day execution history with success vs. failure breakdown.
  • Documentation

    • OpenAPI spec updated to include the new /stats endpoint and execution stats schemas.
  • Tests

    • Added tests covering execution stats aggregation and retrieval.

✏️ Tip: You can customize this high-level summary in your review settings.

- Add ExecutionStat data structure for daily execution counts
- Implement GetExecutionStats and IncrementExecutionStat in storage
- Update SetExecutionDone to track statistics on execution completion
- Add GET /v1/stats API endpoint with configurable days parameter
- Create ExecutionStatsChart React component with stacked area chart
- Integrate statistics graph into UI dashboard
- Add comprehensive tests for execution statistics functionality
- Fix pre-existing import path issue in grpc_test.go
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jan 25, 2026

📝 Walkthrough

Walkthrough

Adds daily execution statistics: new storage API and store implementation, a GET /v1/stats HTTP endpoint, data models and tests, and a React dashboard chart that fetches and displays the last 30 days of execution success/failure counts.

Changes

Cohort / File(s) Summary
API & HTTP layer
dkron/api.go
New statsHandler wired to GET /v1/stats; parses days query (default 30) and returns JSON or 500 on error.
Storage interface
dkron/storage.go
Added GetExecutionStats(ctx context.Context, days int) (*ExecutionStats, error) and IncrementExecutionStat(ctx context.Context, date time.Time, success bool) error.
Store implementation
dkron/store.go
New statsPrefix and helpers; incrementStatTxFunc; added IncrementExecutionStat and GetExecutionStats; integrated non-fatal stats updates into SetExecutionDone.
Data models
dkron/execution_stats.go
New types ExecutionStat (Date, SuccessCount, FailedCount) and ExecutionStats with ExecutionStat.TotalExecutions().
Backend tests
dkron/execution_stats_test.go, dkron/grpc_test.go
New tests covering stat increments, retrieval, ordering, TotalExecutions, and SetExecutionDone integration; minor whitespace tweak in gRPC test.
Frontend: dashboard & chart
ui/src/dashboard/ExecutionStatsChart.tsx, ui/src/dashboard/Dashboard.tsx
New ExecutionStatsChart component fetching last-30-days stats and rendering a stacked area chart; Dashboard imports and renders the chart.
UI build artifact
dkron/ui-dist/index.html
Updated JS asset reference and removed Algolia verification meta tag.
API docs
website/static/openapi/openapi.yaml
Added /stats GET spec and execution_stat / execution_stats schemas.

Sequence Diagram(s)

sequenceDiagram
  participant UI as "Browser UI"
  participant API as "HTTPTransport / API (GET /v1/stats)"
  participant Store as "Store"
  participant KV as "KV storage"

  UI->>API: GET /v1/stats?days=30
  API->>Store: GetExecutionStats(ctx, days)
  Store->>KV: Read keys stats:YYYY-MM-DD...
  KV-->>Store: JSON stat entries (or missing)
  Store-->>API: ExecutionStats JSON
  API-->>UI: 200 OK + stats JSON
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

I hop through days and numbers bright,
I tally wins and fails by night,
I store each date in careful rows,
Then paint the trends where sunlight shows,
A little rabbit charts your flight 🐇📈

🚥 Pre-merge checks | ✅ 1 | ❌ 2
❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Description check ⚠️ Warning The description lists changes made but lacks the 'Proposed changes' section details and has unchecked checkboxes in 'Types of changes' section, indicating incomplete template compliance. Fill in the 'Proposed changes' section with rationale and select appropriate checkboxes (likely 'New feature') to complete the template.
Docstring Coverage ⚠️ Warning Docstring coverage is 20.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main changes: adding execution statistics storage and a dashboard graph visualization.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🤖 Fix all issues with AI agents
In `@dkron/api.go`:
- Around line 553-568: In statsHandler, validate the days query param (daysStr)
after parsing: if strconv.Atoi fails or the parsed days is <= 0 return a 400 Bad
Request with a clear error message; otherwise cap days to a reasonable maximum
(e.g., maxDays := 365) before calling h.agent.Store.GetExecutionStats so
extremely large values are reduced. Update the handler to use the
validated/capped days value and keep the existing error logging for the
GetExecutionStats call.

In `@dkron/execution_stats_test.go`:
- Around line 22-24: The test uses time.Now() to set the variable now (and again
later) which makes the test flaky; replace time.Now() with a fixed UTC time
value (e.g., a time.Date(...) constant) and use that fixed variable wherever now
is used in the file (including the occurrences around lines where now is set and
the later uses at ~128-129) so the test is deterministic across time zones/DST;
update the variable declaration (currently "now") and any assertions that depend
on it (in the test functions in dkron/execution_stats_test.go) to reference this
fixed UTC timestamp.

In `@dkron/store.go`:
- Around line 951-995: The GetExecutionStats method allows an unbounded days
parameter which can lead to large allocations and long loops; add an upper bound
(e.g., maxDays := 365) and clamp days = max(1, min(days, maxDays)) before
allocating stats and iterating. Update the allocation of stats.Stats to use the
clamped days value and iterate that many days using the existing loop logic in
Store.GetExecutionStats so memory and work are limited.

In `@ui/src/dashboard/ExecutionStatsChart.tsx`:
- Around line 33-36: The dateFormatter function currently formats dates in the
user’s local timezone which mismatches the backend’s UTC-day aggregation; update
the dateFormatter (const dateFormatter) to pass timeZone: 'UTC' in the options
to toLocaleDateString (e.g., { month: 'short', day: 'numeric', timeZone: 'UTC'
}) so the frontend labels align with backend UTC truncation.

Comment thread dkron/api.go
Comment on lines +553 to +568
func (h *HTTPTransport) statsHandler(c *gin.Context) {
daysStr := c.DefaultQuery("days", "30")
days, err := strconv.Atoi(daysStr)
if err != nil {
days = 30
}

stats, err := h.agent.Store.GetExecutionStats(c.Request.Context(), days)
if err != nil {
h.logger.WithError(err).Error("api: Unable to get execution stats")
c.AbortWithStatus(http.StatusInternalServerError)
return
}

renderJSON(c, http.StatusOK, stats)
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Validate and cap the days query parameter.
Line 554 accepts any value; negative or very large inputs can lead to unexpected ranges or excessive work. Consider enforcing a positive range and a reasonable maximum (e.g., 365).

🔧 Suggested bounds handling
-	daysStr := c.DefaultQuery("days", "30")
-	days, err := strconv.Atoi(daysStr)
-	if err != nil {
-		days = 30
-	}
+	const (
+		defaultStatsDays = 30
+		maxStatsDays     = 365
+	)
+	daysStr := c.DefaultQuery("days", strconv.Itoa(defaultStatsDays))
+	days, err := strconv.Atoi(daysStr)
+	if err != nil || days <= 0 {
+		days = defaultStatsDays
+	}
+	if days > maxStatsDays {
+		days = maxStatsDays
+	}
🤖 Prompt for AI Agents
In `@dkron/api.go` around lines 553 - 568, In statsHandler, validate the days
query param (daysStr) after parsing: if strconv.Atoi fails or the parsed days is
<= 0 return a 400 Bad Request with a clear error message; otherwise cap days to
a reasonable maximum (e.g., maxDays := 365) before calling
h.agent.Store.GetExecutionStats so extremely large values are reduced. Update
the handler to use the validated/capped days value and keep the existing error
logging for the GetExecutionStats call.

Comment on lines +22 to +24
ctx := context.Background()
now := time.Now()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Stabilize time-dependent tests.
Line 23 and Line 128 use time.Now(), which can be flaky around midnight/DST. Use a fixed UTC time for deterministic results.

🧪 Deterministic time setup
-	now := time.Now()
+	now := time.Date(2025, 1, 2, 12, 0, 0, 0, time.UTC)
...
-	now := time.Now()
+	now := time.Date(2025, 1, 2, 12, 0, 0, 0, time.UTC)

Also applies to: 128-129

🤖 Prompt for AI Agents
In `@dkron/execution_stats_test.go` around lines 22 - 24, The test uses time.Now()
to set the variable now (and again later) which makes the test flaky; replace
time.Now() with a fixed UTC time value (e.g., a time.Date(...) constant) and use
that fixed variable wherever now is used in the file (including the occurrences
around lines where now is set and the later uses at ~128-129) so the test is
deterministic across time zones/DST; update the variable declaration (currently
"now") and any assertions that depend on it (in the test functions in
dkron/execution_stats_test.go) to reference this fixed UTC timestamp.

Comment thread dkron/store.go
Comment thread ui/src/dashboard/ExecutionStatsChart.tsx
@vcastellm vcastellm added this to the v4.1 milestone Jan 25, 2026
vcastellm and others added 2 commits January 28, 2026 19:57
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
@vcastellm
Copy link
Copy Markdown
Member Author

@copilot add the new endpoint to the OpenAPI spec

Copy link
Copy Markdown
Contributor

Copilot AI commented Jan 28, 2026

@vcastellm I've opened a new pull request, #1900, to work on those changes. Once the pull request is ready, I'll request review from you.

* Initial plan

* feat: Add /stats endpoint to OpenAPI specification

Co-authored-by: vcastellm <47026+vcastellm@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: vcastellm <47026+vcastellm@users.noreply.github.com>
@vcastellm
Copy link
Copy Markdown
Member Author

vcastellm commented Jan 28, 2026

@copilot check these errors:

go vet ./...
  shell: /usr/bin/bash -e {0}
# github.com/distribworks/dkron/v4/dkron
Error: dkron/store.go:1001:1: syntax error: non-declaration statement outside function body
# github.com/distribworks/dkron/v4/dkron
# [github.com/distribworks/dkron/v4/dkron]
Error: vet: dkron/store.go:1001:1: expected declaration, found '}'
Error: Process completed with exit code 1.

Copy link
Copy Markdown
Contributor

Copilot AI commented Jan 28, 2026

@vcastellm I've opened a new pull request, #1901, to work on those changes. Once the pull request is ready, I'll request review from you.

…#1901)

* Initial plan

* fix: Remove extraneous closing brace in store.go

Co-authored-by: vcastellm <47026+vcastellm@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: vcastellm <47026+vcastellm@users.noreply.github.com>
@vcastellm vcastellm merged commit 28f91f1 into main Jan 28, 2026
5 checks passed
@vcastellm vcastellm deleted the feature/execution-statistics branch January 28, 2026 19:56
Copilot AI added a commit that referenced this pull request Jan 29, 2026
Merged latest changes from main branch (commit 2b5f80b) into the E2E test PR branch.

Conflict resolution strategy:
- Accepted main branch version for all source files (Go code, UI, configs)
- Preserved E2E test infrastructure (e2e/ directory and all test files)
- Added e2e, e2e-quick, e2e-debug targets back to Makefile
- Kept .github/workflows/e2e.yml workflow file

New features from main now included:
- Redesigned UI with modern professional styling (#1894)
- Execution statistics storage and dashboard graph (#1896)
- Plugin health monitoring in /health endpoint (#1884)
- Retry logic with exponential backoff for AgentRun RPC (#1882)
- Various dependency updates

Co-authored-by: vcastellm <47026+vcastellm@users.noreply.github.com>
vcastellm added a commit that referenced this pull request Jan 29, 2026
* Initial plan

* Merge main branch into E2E test suite PR

Merged latest changes from main branch (commit 2b5f80b) into the E2E test PR branch.

Conflict resolution strategy:
- Accepted main branch version for all source files (Go code, UI, configs)
- Preserved E2E test infrastructure (e2e/ directory and all test files)
- Added e2e, e2e-quick, e2e-debug targets back to Makefile
- Kept .github/workflows/e2e.yml workflow file

New features from main now included:
- Redesigned UI with modern professional styling (#1894)
- Execution statistics storage and dashboard graph (#1896)
- Plugin health monitoring in /health endpoint (#1884)
- Retry logic with exponential backoff for AgentRun RPC (#1882)
- Various dependency updates

Co-authored-by: vcastellm <47026+vcastellm@users.noreply.github.com>

* Fix unresolved merge conflict in ui/src/layout/index.css

Replaced file with clean version from main branch to remove conflict markers.

Co-authored-by: vcastellm <47026+vcastellm@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: vcastellm <47026+vcastellm@users.noreply.github.com>
vcastellm added a commit that referenced this pull request Jan 29, 2026
* Add comprehensive E2E test suite for Dkron API

- Create e2e test infrastructure using Bats (Bash Automated Testing System)
- Add Docker Compose setup for isolated e2e testing environment
- Add 71 tests covering:
  - Health, cluster, leader, and debug endpoints (19 tests)
  - Job CRUD operations including timezone, retries, concurrency (24 tests)
  - Job execution and scheduling (17 tests)
  - Pause/unpause functionality (11 tests)
- Add helper functions for API requests, response parsing, and assertions
- Add test runner script with options for filtering, verbose output, and debugging
- Add Makefile targets: e2e, e2e-quick, e2e-debug

Key findings documented in tests:
- Disabled jobs cannot be manually triggered via /run endpoint
- Pause only blocks new job creation, not scheduled execution
- Timezone jobs require 6-field cron expressions (with seconds)

* Add Algolia site verification meta tag

* Apply suggestion from @coderabbitai[bot]

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* Add GitHub Actions workflow for E2E tests (#1899)

* Initial plan

* Add GitHub Actions workflow for E2E tests

Co-authored-by: vcastellm <47026+vcastellm@users.noreply.github.com>

* Fix workflow: remove invalid tags-ignore and use apt for bats

Co-authored-by: vcastellm <47026+vcastellm@users.noreply.github.com>

* Add explicit permissions to e2e workflow

Co-authored-by: vcastellm <47026+vcastellm@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: vcastellm <47026+vcastellm@users.noreply.github.com>

* Merge main branch into E2E test suite PR (#1902)

* Initial plan

* Merge main branch into PR branch - resolve conflicts

Merged latest changes from main branch (commit 28f91f1) into the E2E test PR branch.

Conflict resolution:
- Accepted main branch version for all source files (Go code, UI, configs)
- Preserved E2E test infrastructure (e2e/ directory and all test files)
- Added e2e, e2e-quick, e2e-debug targets back to Makefile
- Kept .github/workflows/e2e.yml workflow file

New features from main now included:
- Execution statistics storage and dashboard graph
- Plugin health monitoring
- Retry logic with exponential backoff for AgentRun RPC
- Various dependency updates

Co-authored-by: vcastellm <47026+vcastellm@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: vcastellm <47026+vcastellm@users.noreply.github.com>

* Update E2E test to use bare endpoint /v1/jobs/:job (#1897)

* Initial plan

* Update first test to use bare endpoint /v1/jobs/:job

Co-authored-by: vcastellm <47026+vcastellm@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: vcastellm <47026+vcastellm@users.noreply.github.com>

* Fix flaky E2E test using deterministic polling instead of fixed sleep (#1898)

* Initial plan

* Replace sleep 3 with wait_for_execution for deterministic test behavior

Co-authored-by: vcastellm <47026+vcastellm@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: vcastellm <47026+vcastellm@users.noreply.github.com>

* Update dkron/api_test.go

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* Fix syntax error in TestHealthEndpoint causing compilation failure (#1906)

* Initial plan

* Fix syntax error in api_test.go - remove duplicate closing brace

Co-authored-by: vcastellm <47026+vcastellm@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: vcastellm <47026+vcastellm@users.noreply.github.com>

* Fix retry loop skipping when AgentRunMaxRetries is negative (#1905)

* Initial plan

* Fix retry loop to ensure at least one attempt when maxRetries is negative

Co-authored-by: vcastellm <47026+vcastellm@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: vcastellm <47026+vcastellm@users.noreply.github.com>

* Enhance E2E test to validate failed execution success field (#1904)

* Initial plan

* Enhance failed job execution test to assert success=false

Co-authored-by: vcastellm <47026+vcastellm@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: vcastellm <47026+vcastellm@users.noreply.github.com>

* Remove beta dependency by downgrading protoreflect to v1.17.0 (#1903)

* Initial plan

* Downgrade protoreflect from v1.18.0 to v1.17.0 to remove beta v2 dependency

Co-authored-by: vcastellm <47026+vcastellm@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: vcastellm <47026+vcastellm@users.noreply.github.com>

* Add comprehensive E2E test suite for Dkron API (#1907)

* Initial plan

* Merge main branch into E2E test suite PR

Merged latest changes from main branch (commit 2b5f80b) into the E2E test PR branch.

Conflict resolution strategy:
- Accepted main branch version for all source files (Go code, UI, configs)
- Preserved E2E test infrastructure (e2e/ directory and all test files)
- Added e2e, e2e-quick, e2e-debug targets back to Makefile
- Kept .github/workflows/e2e.yml workflow file

New features from main now included:
- Redesigned UI with modern professional styling (#1894)
- Execution statistics storage and dashboard graph (#1896)
- Plugin health monitoring in /health endpoint (#1884)
- Retry logic with exponential backoff for AgentRun RPC (#1882)
- Various dependency updates

Co-authored-by: vcastellm <47026+vcastellm@users.noreply.github.com>

* Fix unresolved merge conflict in ui/src/layout/index.css

Replaced file with clean version from main branch to remove conflict markers.

Co-authored-by: vcastellm <47026+vcastellm@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: vcastellm <47026+vcastellm@users.noreply.github.com>

---------

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com>
Co-authored-by: vcastellm <47026+vcastellm@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants